﻿/*
 * LINQ to LDAP
 * http://linqtoldap.codeplex.com/
 * 
 * Copyright Alan Hatter (C) 2010-2012
 * alan.hatter@gmail.com - http://hattercoding.blogspot.com/
 * 
 * This project is subject to licensing restrictions. Visit http://linqtoldap.codeplex.com/license for more information.
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using LinqToLdap.Exceptions;

namespace LinqToLdap.Mapping
{
    /// <summary>
    /// Uses attributes to map a class
    /// </summary>
    /// <typeparam name="T">The class to map</typeparam>
    public class AttributeClassMap<T> : ClassMap<T> where T : class 
    {
        /// <summary>
        /// Maps <typeparamref name="T"/> using <see cref="DirectorySchemaAttribute"/> 
        /// and <see cref="DirectoryAttributeAttribute"/>
        /// </summary>
        public AttributeClassMap()
        {
            var type = typeof(T);
            var schemaAttribute = type
                .GetCustomAttributes(typeof(DirectorySchemaAttribute), true)
                .Cast<DirectorySchemaAttribute>()
                .FirstOrDefault();

            if (schemaAttribute == null)
            {
                throw new MappingException("DirectorySchemaAttribute not found for " + typeof(T).FullName);
            }

            NamingContext(schemaAttribute.NamingContext);
            ObjectCategory(schemaAttribute.ObjectCategory);
            ObjectClasses(schemaAttribute.ObjectClasses);
            
            var properties = type.GetProperties(Flags)
                .Where(p => p.GetCustomAttributes(typeof(DirectoryAttributeAttribute), true).Any() &&
                            p.GetGetMethod() != null && p.GetSetMethod() != null)
                .Select(p => 
                        new KeyValuePair<DirectoryAttributeAttribute, PropertyInfo>(
                            p.GetCustomAttributes(typeof (DirectoryAttributeAttribute), true)
                                .Cast<DirectoryAttributeAttribute>()
                                .FirstOrDefault(), 
                            p));

            properties.ToList()
                .ForEach(p =>
                             {
                                 var property = MapNonGeneric(p.Value)
                                     .Named(p.Key.AttributeName);

                                 if (p.Key.EnumStoredAsInt)
                                     property.EnumStoredAsInt();

                                 if (p.Key.StoreGenerated)
                                     property.StoreGenerated();

                                 if (p.Key.ReadOnly)
                                     property.ReadOnly();

                                 property.DateTimeFormat(p.Key.DateTimeFormat);
                             });

            var distinguishedName = type.GetProperties(Flags)
                .Where(p => p.GetCustomAttributes(typeof (DistinguishedNameAttribute), true).Any() &&
                                                     p.GetGetMethod() != null && p.GetSetMethod() != null)
                .Select(p => new Tuple<PropertyInfo, DistinguishedNameAttribute>(p,
                    p.GetCustomAttributes(typeof(DistinguishedNameAttribute), true).Cast<DistinguishedNameAttribute>().First()))
                .FirstOrDefault();

            if (distinguishedName != null)
            {
                DistinguishedName(distinguishedName.Item1, distinguishedName.Item2.AttributeName);
            }
        }
    }
}
